package org.boz.dial;

public class LispPrint {
	private static void parseEvalPrint(LispInterpreter interpreter, String lisp) {
		System.out.println(interpreter.parseEval(lisp));
	}

	public static void main(String[] args) {
		LispInterpreter interpreter = new LispInterpreter();
		System.out.println("Hello World");
		LispObject o = new LispInt(4);
		System.out.println(o);
		LispObject o2 = new LispCons(new LispInt(1), new LispInt(2));
		System.out.println(o2);
		LispObject o3 = new LispCons(new LispSym("monkey"), o2);
		System.out.println(o3);
		System.out.println(o3.car());
		System.out.println(o3.cdr());
		System.out.println(o3.cdr().car());

		System.out.println("Testing eval");

		System.out.println(interpreter.eval(o));
		LispObject o4 = new LispCons(LispPrimitives.LispIf, new LispCons(
				LispPrimitives.nil, new LispCons(new LispInt(1), new LispCons(
						new LispInt(2), LispPrimitives.nil))));
		System.out.println(o4);
		System.out.println(interpreter.eval(o4));
		LispObject o5 = new LispCons(LispPrimitives.LispIf, new LispCons(
				LispPrimitives.tee, new LispCons(new LispInt(1), new LispCons(
						new LispInt(2), LispPrimitives.nil))));
		System.out.println(interpreter.eval(o5));

		System.out.println("Testing quote");
		LispObject o6 = new LispCons(LispPrimitives.LispQuote, new LispCons(
				new LispInt(1), LispPrimitives.nil));

		System.out.println(interpreter.eval(o6));

		System.out.println("Testing procs");
		LispObject empty_env = new LispCons(new LispCons(LispPrimitives.nil,
				LispPrimitives.nil), LispPrimitives.nil);
		LispObject o7 = new LispCons(new LispProcedure(LispPrimitives.nil,
				new LispCons(o4, LispPrimitives.nil), empty_env),
				LispPrimitives.nil);
		System.out.println(o7);
		System.out.println(interpreter.eval(o7));

		System.out.println("Testing parser");
		System.out
				.println(interpreter.parse("( '(1 2 3) (lambda () ((foo))))"));
		parseEvalPrint(interpreter, "(if t 1 2)");
		parseEvalPrint(interpreter, "(if () 1 2)");
		System.out.println(interpreter.parse("(\"hello\" \" world\")"));

		System.out.println("Testing lambda");
		parseEvalPrint(interpreter, "((lambda () 1))");

		parseEvalPrint(interpreter, "((lambda (x) x) 2)");

		System.out.println("Testing set");
		parseEvalPrint(interpreter, "(define x 7)");
		parseEvalPrint(interpreter, "(set x x)");

		System.out.println("Testing funcs");
		parseEvalPrint(interpreter, "(define foo (lambda (x) (if x 1 2)))");
		parseEvalPrint(interpreter, "(foo t)");
		parseEvalPrint(interpreter, "(foo ())");
		System.out.println("Testing primitives");
		parseEvalPrint(interpreter, "(+ 1 2)");
		parseEvalPrint(interpreter, "(- 5 2)");
		parseEvalPrint(interpreter, "(* 2 7)");
		parseEvalPrint(interpreter, "(/ 8 2)");
		parseEvalPrint(interpreter, "(= 1 1)");
		parseEvalPrint(interpreter, "(= 1 2)");
		parseEvalPrint(interpreter, "(car (quote (1 2)))");
		parseEvalPrint(interpreter, "(cdr (quote (1 2)))");
		parseEvalPrint(interpreter, "(cons 1 2))");
		parseEvalPrint(interpreter, "(concat \"hello \" \"world\" \".\")");
		parseEvalPrint(interpreter, "(string-equal \"hello\" \"hello\")");
		parseEvalPrint(interpreter, "(string-equal \"hello\" \"world\")");

		parseEvalPrint(interpreter, "(:new \"java.lang.String\")");

		System.out.println("Testing stuff");
		parseEvalPrint(interpreter,
				"(+ (car (quote (1 2))) (car (quote (2 1))))");

		System.out.println("Testing stuff2");
		parseEvalPrint(interpreter, "(if (= 1 2) (cons 1 2) (cons 3 4))");
		System.out.println("Testing factorial");
		parseEvalPrint(interpreter,
				"(define factorial (lambda (x) (if (= x 1) x (* x (factorial (- x 1))))))");
		parseEvalPrint(interpreter, "(factorial 6)");

		System.out.println("Testing java interaction");
		parseEvalPrint(interpreter,
				"(cons (:new \"java.lang.String\") (:new \"java.lang.String\"))");
		parseEvalPrint(interpreter,
				"(:invoke (:new \"java.lang.String\") \"length\")");
		parseEvalPrint(interpreter,
				"(:invoke (:invoke (:new \"java.lang.String\") \"getClass\") \"getName\")");

		parseEvalPrint(interpreter, "(:new \"java.lang.String\" \"monkey\")");
		parseEvalPrint(interpreter,
				"(:invoke (:new \"java.lang.String\" \"hello \") \"length\")");
		parseEvalPrint(
				interpreter,
				"(:invoke (:new \"java.lang.String\" \"hello\") \"equals\" (:new \"java.lang.String\" \"hello\"))");
		parseEvalPrint(
				interpreter,
				"(:invoke (:new \"java.lang.String\" \"hello\") \"equals\" (:new \"java.lang.String\" \"world\"))");

		parseEvalPrint(interpreter, "(:invoke \"hello\" \"length\")");

		System.out.println("Testing proper tail recursion");
		parseEvalPrint(
				interpreter,
				"(define factimpl (lambda (x acc) (if (= x 1) acc (factimpl (- x 1) (* x acc)))))");
		parseEvalPrint(interpreter,
				"(define factorial2 (lambda (x) (factimpl x 1)))");
		parseEvalPrint(interpreter, "(factorial2 8)");

		System.out.println("Testing let");
		parseEvalPrint(interpreter, "(let ((x 1)(y 2)) (+ x y) x)");
		parseEvalPrint(interpreter, "x");
		System.out.println("Testing closures");
		parseEvalPrint(interpreter,
				"(define close (let ((closevar 1)) (lambda () (set closevar (+ closevar 1)))))");
		parseEvalPrint(interpreter, "(close)");
		parseEvalPrint(interpreter, "(close)");
		// parseEvalPrint(interpreter, "closevar"); // unbound symbol.

		System.out.println("Testing macros");
		parseEvalPrint(interpreter, "(defmacro mac1 (x) '(if x t ()))");
		// parseEvalPrint(interpreter, "(macro-expand mac1 1)");
		// parseEvalPrint(interpreter, "(mac1 1)");
		// parseEvalPrint(interpreter, "(mac1 2)");
		// TODO:
		// - Macros
		// - Cleanup
		// - Improved printing (list rather than dot notation)

	}
}
